var baseUrl = "";
var ui = 'default';
var test = false;
var notNull = function () {
  return arguments[0] != undefined && arguments[0] != null
}
var getJsonLength = function (json) {
  if (!json) return 0;
  var length = 0;
  for (var i in json) {
    length++;
  }
  return length;
}

var addClass = function (elem, className) {
  if (!notNull(elem)) {
    return;
  }
  var oldClassName = elem.className;
  if (!oldClassName) {
    elem.className = className;
    return;
  }
  var olds = oldClassName.split(" ");
  for (var i in olds) {
    if (olds[i] == className) {
      return;
    }
  }
  elem.className += " " + className;
}

var removeClass = function (elem, className) {
  if (!notNull(elem)) {
    return;
  }
  var oldClassName = elem.className;
  if (!oldClassName) {
    return;
  }
  var newClassName = '';
  var olds = oldClassName.split(" ");
  for (var i in olds) {
    if (olds[i] == className) {
      continue;
    }
    newClassName += olds[i] + " ";
  }
  newClassName = newClassName.substring(0, newClassName.length - 1);
  elem.className = newClassName;
}

var isFunction = function (func) {
  return notNull(func) && typeof (func) == 'function';
}

var exist = function (array, target) {
  for (var i in array) {
    if (array[i] == target) {
      return true;
    }
  }
  return false;
}

//克隆一个对象，可选择深度，point设置为1则只克隆当前的，设置为2则多加一层子层，为-1则复制全部
var clone = function (src, point) {
  if (src == null) {
    return null;
  }
  if (point == 0) {
    return null;
  }
  var target = {};
  if (src instanceof Array) {
    target = [];
  }
  for (var i in src) {
    if (typeof (src[i]) == 'object') {
      target[i] = clone(src[i], point - 1);
    } else {
      target[i] = src[i];
    }
  }

  return target;
}

var object;

function Tree(option) {
  option = clone(option, -1);
  this.data = option.data || [], this.isAsync = !notNull(option.data), this.mainNode = document.createElement("div"),
    this.parent = document.querySelector(option.elem), this.allId = [], this.point = 0, this.format = {
    name: 'name',
    childs: 'childs',
    unfold: 'unfold',
    type: 'type',
    title: 'title',
    id: "id",
    hide: 'hide'
  }, this.allData = {}, this.isDbClick, this.timeOut = 0;
  //文件工具栏 文件夹工具栏
  if (option.toolbar) {
    if (notNull(option.foldTools)) {
      foldTools = option.foldTools;
      if (notNull(option.tools)) {
        tools = option.tools;
      } else {
        tools = clone(foldTools, -1);
        //tools.splice(0, 1);
      }
    } else {
      //工具栏
      foldTools = [{name: '添加', type: 'add', title: '添加节点'}, {name: '修改', type: 'update', title: '修改节点'}, {
        name: '删除',
        type: 'delete',
        title: '删除节点'
      }];
      tools = clone(foldTools, -1);
      tools.splice(0, 1);
    }
  }

  if (!notNull(option.loadAll)) {
    option.loadAll = true;
  }

  object=this;

  if (notNull(option.format) && typeof (option.format) == 'function') {
    option.format(this.format);
  }

  this.incidents = ['click', 'dblclick', 'mouseleave', 'mouseenter'];
  this.allIncident = this.incidents;
  this.mainNode.className = "tree-main";
  this.load();
}

Tree.prototype = {
  Icon: {
    dir_fold: {
      src: baseUrl + "img/" + ui + "/dir_fold.png", width: 16, height: 16
    },
    dir_unfold: {
      src: baseUrl + "img/" + ui + "/dir_unfold.png", width: 16, height: 16
    },
    option: {
      src: baseUrl + "img/" + ui + "/option.png", width: 16, height: 16
    }, icon_fold: {
      src: baseUrl + "img/" + ui + "/icon_fold.png", width: 16, height: 16
    }, icon_unfold: {
      src: baseUrl + "img/" + ui + "/icon_unfold.png", width: 16, height: 16
    }
  },
  mainNode: null,
  div_Load: null,
  incidents: null,
  allIncident: null,
  allId: null,
  data: null,
  allData: null,
  format: null,
  parent: null,
  isDbClick: null,
  point: null,
  timeOut: null,
  tools: null,
  foldTools: null,
  isAsync: null,
  Node: function (elem, isParent) {
    this.elem = elem;
    this.data = object.getDataById(elem.getAttribute('tree-id'));
    this.isParent = isParent || this.data[object.format.type] || object.hasChild(elem);
    this.id = this.data[object.format.id];
    this.name = this.data[object.format.name];
    this.title = this.data[object.format.title] || this.name;
    var checked, parent, childs, next, prev;
    this.childs = function () {
      if (!notNull(childs)) {
        childs = [];
        var elems = this.elem.nextElementSibling.childNodes;
        for (var i in elems) {
          var li = elems[i];
          if (li instanceof HTMLLIElement) {
            var elem = li.firstElementChild;
            childs[childs.length] = new object.Node(elem);
          }
        }
      }
      return childs;
    }
    this.checked = function () {
      if (!notNull(checked)) {
        checked = object.checked(this);
      }
      return checked;
    }
    this.parent = function () {
      if (notNull(parent)) {
        return parent;
      }
      if (this.elem.parentNode.parentNode.parentNode.className.indexOf('tree-main') == -1) {
        parent = new object.Node(this.elem.parentNode.parentNode.previousElementSibling, true);
        return parent;
      } else {
        return null;
      }
    }

    this.next = function () {
      if (!notNull(next)) {
        var nextLi = this.elem.parentNode.nextElementSibling;
        if (notNull(nextLi)) {
          next = new object.Node(nextLi.firstElementChild);
        } else {
          return null;
        }
      }
      return next;
    }

    this.prev = function () {
      if (!notNull(prev)) {
        var prevLi = this.elem.parentNode.previousElementSibling;
        if (notNull(prevLi)) {
          prev = new object.Node(prevLi.firstElementChild);
        } else {
          return null;
        }
      }
      return prev;
    }

    this.hasChild = function () {
      if (!this.isParent) {
        return false;
      }
      return object.hasChild(this.elem);
    }

    this.foldAll = function () {
      object.foldAll(this);
    }

    this.addEventListener = function (type, func) {
      object.addEventListener(this, type, func);
    }

    this.check = function () {
      if (option.checkbox) {
        object.checkClick(this);
      }
    }

    this.addNode = function (data) {
      object.addNode(this, data);
    }

    this.addNodeByInterface = function (option, func) {
      object.addNodeByInterface(this, option, func)
    }

    this.remove = function () {
      object.remove(this);
    }

    this.clear = function () {
      object.clear(this);
    }

    this.unFold = function () {
      object.nodeUnfold(this, false);
    }

    this.fold = function () {
      object.nodeFold(this, false);
    }

  },
  ajax: function (option) {
    var request = new XMLHttpRequest();
    request.open(option.method, option.url, true);
    request.setRequestHeader("Access-Control-Allow-Origin", "*");
    request.setRequestHeader("Access-Control-Allow-Credentials", true);
    try {
      request.send(option.data || "");
    } catch (e) {
      if (isFunction(option.error)) {
        option.error(e);
      }
    }
    request.onreadystatechange = function () {
      if (request.status == 200 && request.readyState == 4) {
        if (isFunction(option.callback)) {
          if (option.responseType == 'json') {
            if (notNull(request.responseText) && request.responseText[0] == '{' || request.responseText[0] == '[') {
              option.callback(JSON.parse(request.responseText));
            } else {
              option.callback(request.responseText);
            }
          } else {
            option.callback(request.responseText);
          }
        }
      } else {
        if (request.status != 200) {
          if (isFunction(option.error)) {
            option.error(request.status);
          }
        }
      }
    }
  },
  load: function () {
    this.loadInfo();
    if (!notNull(this.data) || this.data.length == 0 && notNull(option.async)) {
      var newAjax = option.async;
      newAjax.callback = function (data) {
        object.data = data;
        if (JSON.stringify(object.data).substr(0, 1) == '{') {
          var array = [];
          array[0] = object.data;
          object.data = array;
        }
        object.init("init");
      }
      newAjax.error = function (e) {
        console.log(e);
        this.div_Load.firstElementChild.innerText = option.loadText || "加载失败！";
      }
      newAjax.responseType = 'json';
      this.ajax(newAjax);
    }
  },
  createElement: function (elem, data, unfold) {
    if (data && data.length > 0) {
      var ul = this.createUl();
      if (notNull(elem.lastElementChild) && elem.lastElementChild.nodeName.toUpperCase() == 'UL') {
        ul = elem.lastElementChild;
      }
      for (var i in data) {
        var node = data[i];
        if (isFunction(option.template)) {
          option.template(node);
        }
        var li;
        //如果没有子节点或者子节点数量为0
        if (!notNull(node[this.format.childs]) || node[this.format.childs].length == 0) {
          //如果指定类型是文件夹
          if (node.type == 'folder' || node[this.format.type] == true) {
            var hasContent = false;
            if (node[this.format.hasContent]) {
              hasContent = true;
            }
            li = this.createFolder(node, hasContent);
            if (option.toolbar) {
              this.addTools(true, li);
            }
            //this.createElement(nodeDoc, node.childs, node.unfold);
          } else {
            li = this.createNode(node);
            if (option.toolbar) {
              this.addTools(false, li);
            }
          }

        } else {
          li = this.createFolder(node);
          if (option.toolbar) {
            this.addTools(true, li);
          }
          if (option.loadAll) {
            //需要优化,不建议使用此方式
            object.createElement(li, node[object.format.childs], node[object.format.unfold]);
          } else {
            li.setAttribute('after-data', JSON.stringify(node));
          }
        }
        if (node[this.format.unfold]) {
          unfold = true;
        }
        if (node[this.format.hide]) {
          addClass(li, 'tree-hide');
        }
        ul.appendChild(li);
      }
      elem.appendChild(ul);
      //如果展开，即将前面的也展开
      if (unfold) {
        addClass(ul, 'tree-fold')
      }
    }
  },
  init: function (arg) {
    if (this.isAsync && !notNull(arg) && arg != 'init') {
      return;
    }
    this.parent.appendChild(this.mainNode);
    this.createElement(this.mainNode, this.data, true);
    this.div_Load.parentNode.removeChild(this.div_Load)
    var nodes = document.getElementsByClassName('tree-fold');
    if (nodes.length > 0) {
      for (var i in nodes) {
        this.loadUnFold(nodes[i]);
      }
    }

    if (notNull(option.loadCallBack) && typeof (option.loadCallBack) == 'function') {
      option.loadCallBack(object);
    }
    this.mainNode.style.minWidth = this.parent.scrollWidth + "px";
  },
  addNodeByInterface: function (node, option, func) {
    var ul, elem = node;
    if (node instanceof object.Node) {
      elem = node.elem;
    }
    if (!notNull(elem.nextElementSibling)) {
      ul = this.createUl();
      elem.parentNode.appendChild(ul);
    } else {
      ul = elem.nextElementSibling;
    }
    var div = document.createElement('div');
    div.className = 'tree-wait-div';
    div.innerText = '正在加载数据，请稍后...';
    var li = document.createElement('li');
    li.className = 'tree-li tree-wait';
    li.appendChild(div);
    ul.insertBefore(li, ul.firstChild);
    option.callback = function (data) {
      if (typeof data == 'text') {
        option.error('未知');
        return;
      }
      /*if (JSON.stringify(data).substr(0, 1) == '{') {
        var temp = [];
        temp[0] = data;
        data = temp;
      }*/
      object.addNode(elem, data);
      ul.removeChild(li);
      if (isFunction(func)) {
        func();
      }
    }
    option.error = function (e) {
      div.innerText = '加载数据失败！异常：' + e;
    }
    option.responseType = 'json';
    this.ajax(option);
  },
  addNode: function (node, datas) {
    var elem = node;
    if (node instanceof object.Node) {
      elem = node.elem;
    }
    if (!notNull(elem)) {
      return;
    }
    //elem=elem.firstElementChild;
    if (JSON.stringify(datas).substr(0, 1) == '{') {
      var array = [];
      array[0] = datas;
      datas = array;
    }
    var ul;
    if (!notNull(elem.nextElementSibling)) {
      ul = this.createUl();
      elem.parentNode.appendChild(ul);
    } else {
      ul = elem.nextElementSibling;
    }
    for (var i in datas) {
      var li;
      var data = datas[i];
      if (isFunction(option.template)) {
        option.template(data);
      }
      if (data[this.format.type] == 'folder' || data[this.format.type] == true || this.hasChildArray(data)) {
        li = this.createFolder(data, true);
        if (this.hasChildArray(data)) {
          this.addNode(li.firstElementChild, data[this.format.childs]);
        }
        this.nodeFold(li.firstElementChild, false);
        if (option.toolbar) {
          this.addTools(true, li);
        }
      } else {
        li = this.createNode(data);
        if (option.toolbar) {
          this.addTools(false, li);
        }
      }
      ul.appendChild(li);
    }
  },
  hide: function () {
    var hides = document.querySelectorAll('.tree-show.tree-hide');
    for (var i in hides) {
      if (hides[i] instanceof HTMLElement) {
        removeClass(hides[i], 'tree-show');
      }
    }
  },
  show: function () {
    var hides = document.querySelectorAll('.tree-hide');
    for (var i in hides) {
      if (hides[i] instanceof HTMLElement) {
        addClass(hides[i], 'tree-show');
      }
    }
  },
  loadUnFold: function (node) {
    var elem = node.elem;
    if (elem instanceof HTMLElement) {
      if (elem.parentNode.className.indexOf('tree-main') == -1) {
        if (elem.className.indexOf('tree-ul') != -1) {
          //addClass(elem, 'tree-fold');
          this.nodeUnfold(elem.previousElementSibling, false);
        }
        this.loadUnFold(elem.parentNode);
      }
    }
  },
  createButton: function (btn) {
    var button = document.createElement('button');
    button.className = 'tree-toolbar-btn ' + btn.type;
    if (notNull(btn.name)) {
      button.innerText = btn.name;
    } else {
      button.innerText = '操作';
    }
    if (notNull(button.title)) {
      button.title = btn.title;
    } else {
      button.title = btn.innerText;
    }
    button.onclick = function () {
      if (isFunction(option.toolClick)) {
        var ele = this.parentNode.parentNode;
        option.toolClick(btn.type, new object.Node(ele));
      }
    };
    return button;
  },
  clear: function (node) {
    if (!notNull(node)) {
      var ul = this.mainNode.firstElementChild;
      var lis = ul.childNodes;
      if(!notNull(ul)){
        return;
      }
      var count=lis.length;
      for (var i=0;i<count;i++){
        var li=lis.item(0);
        if(li instanceof HTMLLIElement){
          ul.removeChild(li);
        }
      }
    } else {
      if (node instanceof object.Node) {
        var ul = node.elem.nextElementSibling;
        if(!notNull(ul)){
          return;
        }
        var lis=ul.childNodes;
        var count=lis.length;
        for (var i=0;i<count;i++){
          var li=lis.item(0);
          if(li instanceof HTMLLIElement){
            ul.removeChild(li);
          }
        }
      }
    }
  },
  remove: function (node) {
    if (!notNull(node)) {
      this.mainNode.removeChild(this.mainNode.firstElementChild);
    } else {
      if (node instanceof object.Node) {
        var parent = node.elem.parentNode;
        parent.parentNode.removeChild(parent);
      }
    }
  },
  reload: function (newOption) {
    if (!notNull(newOption) || !notNull(newOption.elem)) {
      return;
    }
    if (notNull(newOption)) {
      option = newOption;
    }
    this.mainNode.removeChild(this.mainNode.firstElementChild);
    this.allData = [];
    this.allId = [];
    this.point = 0;
    this.data = null;
    this.load();
    this.init();
  },
  getChecked: function () {

    if (!option.checkbox) {
      return [];
    }
    var spans = document.getElementsByClassName('tree-checkbox-background-all');
    var ids = new Set();
    if (option.loadAll) {
      ids = [];
    }
    if (spans.length > 0) {
      for (var i in spans) {
        var span = spans[i];
        if (span instanceof HTMLSpanElement) {
          var div = span.parentNode.parentNode;
          if (option.loadAll) {
            ids[ids.length] = new object.Node(div.parentNode.parentNode);
          } else {
            ids.add(div.getAttribute('tree-check-id'));
          }
          var data = div.parentNode.parentNode.parentNode.getAttribute('after-data');
          if (notNull(data) && !option.loadAll) {
            data = JSON.parse(data);
            this.getNotLoadId(data[this.format.childs], ids);
          }
        }
      }
    }
    return ids;
  },
  addTools: function (fold, li) {
    var div = document.createElement('div');
    div.className = 'tree-toolbar';
    var tool = this.tools;
    if (fold) {
      tool = this.foldTools;
    }

    for (var i in tool) {
      var btn = this.createButton(tool[i]);
      div.appendChild(btn);
    }
    /*    if(fold){
          li.firstElementChild.insertBefore(div,li.firstElementChild.nextElementSibling);
        }else{*/
    li.firstElementChild.appendChild(div);
    //  }
  },
  checked: function (node) {
    if (option.checkbox) {
      var background = node.elem.firstElementChild.firstElementChild.className;
      if (background == 'tree-fold-icon') {
        background = node.elem.firstElementChild.firstElementChild.nextElementSibling.firstElementChild.firstElementChild.className;
      }
      if (background.indexOf('tree-checkbox-background-all') != -1) {
        return true;
      } else {
        return false;
      }
    } else {
      return false;
    }
  },
  checkClick: function (node) {
    var checkbox = node.elem.firstElementChild.firstElementChild;
    if (checkbox.className.indexOf("tree-fold-icon") != -1) {
      checkbox = checkbox.nextElementSibling;
    }
    this.checkboxSelect(checkbox, true, 0, true, true, true);
  },
  createCheckBox: function (id) {
    var div = document.createElement("div");
    addClass(div, 'tree-checkbox');
    var border = document.createElement("span");
    addClass(border, 'tree-checkbox-border');
    var background = document.createElement('span');
    addClass(background, 'tree-checkbox-background');
    border.appendChild(background);
    div.appendChild(border);
    div.setAttribute('tree-check-id', id);
    div.onclick = function () {
      object.checkboxClick(this);
    }
    return div;
  },
  createSubject: function (node, iconOption) {
    var Newdiv = document.createElement("div");
    Newdiv.className = "tree-subject";
    var div = document.createElement("div");
    var span = document.createElement("span");

    var newNode = clone(node, 1);
    delete newNode[this.format.childs];

    if (this.format.data == 'all') {
      div.setAttribute("tree-data", JSON.stringify(newNode));
    } else {
      //判断是否有data属性需要赋值
      if (notNull(node[this.format.data])) {
        Newdiv.setAttribute("tree-data", node[this.format.data]);
      }
    }
    var tree_id;
    //判断是否含有id属性
    if (notNull(node[this.format.id])) {
      node[this.format.id] = parseInt(node[this.format.id]);
      if (!exist(this.allId, node[this.format.id]) || option.compelCustom) {
        tree_id = node[this.format.id];
        this.allId[this.allId.length] = tree_id;
      } else {
        tree_id = this.generatorTreeId();
      }
    } else {
      Newdiv.setAttribute('tree-id', this.generatorTreeId());
    }
    Newdiv.setAttribute('tree-id', tree_id);
    if (option.checkbox) {
      var check = this.createCheckBox(tree_id);
      div.appendChild(check);
    }

    if (iconOption && getJsonLength(iconOption) > 1) {
      var img = this.createIcon(iconOption);
      div.appendChild(img);
    }
    span.className = "tree-title";
    if (!notNull(node[this.format.name])) {
      node[this.format.name] = "节点";
    }
    span.innerHTML = node[this.format.name];
    if (notNull(node[this.format.title])) {
      div.title = node[this.format.title];
    } else {
      div.title = node[this.format.name];
    }
    var suffix = 'gm_';
    for (var j in this.allIncident) {
      var type = this.allIncident[j];
      var arg = type;
      if (type == 'dblclick') {
        arg = 'dbclick';
      }
      if (notNull(option[suffix + arg]) && typeof (option[suffix + arg]) == 'function') {
        this.addEventListener(Newdiv, type, option[suffix + arg]);
      }
    }
    this.addData(tree_id, newNode);
    div.appendChild(span);
    Newdiv.appendChild(div);
    return Newdiv;
  },
  createUl: function () {
    var ul = document.createElement("ul");
    ul.className = "tree-ul";
    return ul;
  },
  createNode: function (node) {
    var li = document.createElement("li");
    li.className = "tree-li tree-node";
    var subject = this.createSubject(node, this.Icon.option);

    var suffix = 'node_';
    for (var i in this.incidents) {
      var type = this.incidents[i];
      var arg = type;
      if (type == 'dblclick') {
        arg = 'dbclick';
      }
      if (notNull(option[suffix + arg]) && typeof (option[suffix + arg]) == 'function') {
        this.addEventListener(subject, type, option[suffix + arg]);
      }
    }
    li.appendChild(subject);
    return li;
  },
  addEventListener: function (node, type, func) {
    var elem = node;
    if (node instanceof object.Node) {
      elem = node.elem;
    }

    function event() {
      if (isFunction(func)) {
        if (type == 'click') {
          object.isDbClick = false;
          setTimeout(function () {
            if (object.isDbClick) {
              return;
            }
            func(new object.Node(elem), object);
          }, object.timeOut);
          return;
        } else if (type == 'dbclick') {
          object.isDbClick = true;
        }
        func(new object.Node(elem), object);
      }
    }

    if (document.addEventListener) {
      elem.addEventListener(type, event);
    } else if (document.attachEvent) {
      elem.attachEvent('on' + type, event);
    }
  },
  createFolder: function (node, isUnfold) {
    var li = document.createElement("li");
    li.className = "tree-li";
    var subject;
    var icon;
    if (isUnfold || node[this.format.unfold]) {
      icon = this.createIcon(this.Icon.icon_fold);
      icon.setAttribute('fold', true);
      subject = this.createSubject(node, this.Icon.dir_fold);
      if (isUnfold) {
        subject.firstElementChild.src = this.Icon.dir_unfold.src;
        icon.src = this.Icon.icon_unfold.src;
      }
    } else {
      icon = this.createIcon(this.Icon.icon_unfold);
      icon.setAttribute('fold', false);
      subject = this.createSubject(node, this.Icon.dir_unfold);
    }
    addClass(icon, 'tree-fold-icon');
    removeClass(icon, 'tree-title-icon');

    function click(elem) {
      if (elem.getAttribute("fold") == 'true') {
        object.nodeFold(elem.parentNode.parentNode, true);
      } else {
        object.nodeUnfold(elem.parentNode.parentNode, true);
      }
    }

    if (document.addEventListener) {
      icon.addEventListener('click', function () {
        object.isDbClick = false;
        var elem = this;
        setTimeout(function () {
          click(elem);
        }, object.timeOut);
      });
    } else if (subject.attachEvent) {
      icon.attachEvent('onclick', function () {
        object.isDbClick = false;
        var elem = this;
        setTimeout(function () {
          click(elem);
        }, object.timeOut);
      });
    }
    subject.firstElementChild.insertBefore(icon, subject.firstElementChild.firstElementChild);

    function dbclick() {
      object.isDbClick = true;
      if (this.firstElementChild.getAttribute('fold') == 'true') {
        object.nodeFold(this.parentNode, true);
      } else {
        object.nodeUnfold(this.parentNode, true);
      }
      if (notNull(option.folder_dbclick) && typeof (option.folder_dbclick) == 'function') {
        option.folder_dbclick(new object.Node(this.parentNode), object);
      }
    }

    if (document.addEventListener) {
      subject.firstElementChild.addEventListener('dblclick', dbclick);
    } else if (document.attachEvent) {
      subject.firstElementChild.attachEvent('ondblclick', dbclick);
    }
    var suffix = 'folder_';
    for (var i in this.incidents) {
      var type = this.incidents[i];
      if (type == 'dblclick') {
        continue;
      }
      if (notNull(option[suffix + type]) && typeof (option[suffix + type]) == 'function') {
        this.addEventListener(subject, type, option[suffix + type]);
      }
    }
    li.appendChild(subject);
    return li;
  },
  foldAll: function (node) {
    var elem = node;
    if (node instanceof object.Node) {
      elem = node.elem;
    }
    if (notNull(elem) && elem instanceof HTMLElement) {
      this.nodeUnfold(elem, false);
      var ul = elem.nextElementSibling;
      if (notNull(ul)) {
        var lis = ul.childNodes;
        for (var i in lis) {
          var li = lis.item(i);
          if (li instanceof HTMLElement) {
            this.nodeUnfold(li.firstElementChild, false);
            if (notNull(li.firstElementChild.nextElementSibling)) {
              this.foldAll(li.firstElementChild);
            }
          }
        }
      }
    }
  },
  getNodeById: function (id) {
    var elem = document.querySelector('.tree-subject[tree-id="' + id + '"]');
    if (notNull(elem)) {
      return new object.Node(elem);
    }
    return null;
  },
  generatorTreeId: function () {
    if (!this.allId) {
      this.allId = [];
    }
    this.point++;
    if (exist(this.allId, this.point)) {
      return this.generatorTreeId();
    }
    this.allId[this.allId.length] = this.point;
    return this.point;
  },
  hasChild: function (elem) {
    if (elem instanceof HTMLElement) {
      return notNull(elem.nextElementSibling);
    } else if (elem instanceof object.Node) {
      return notNull(elem.elem.nextElementSibling);
    } else {
      return false;
    }
  },
  nodeFold: function (elem, call, unfold) {
    if (elem instanceof object.Node) {
      elem = elem.elem;
    }

    var icon = elem.firstElementChild.firstElementChild;
    if (!notNull(icon.className) || icon.className.indexOf('tree-title-icon') != -1) {
      return;
    }
    var fold = icon.nextElementSibling;
    if (option.checkbox) {
      fold = fold.nextElementSibling;
    }
    icon.setAttribute('fold', false);
    icon.src = this.Icon.icon_unfold.src;
    if (!notNull(elem.nextElementSibling)) {
      fold.src = this.Icon.dir_fold.src;
    } else {
      fold.src = this.Icon.dir_unfold.src;
    }
    if (unfold) {
      fold.src = this.Icon.dir_unfold.src;
    }
    removeClass(elem.nextElementSibling, 'tree-fold');
    if (call) {
      if (isFunction(option.unfold)) {
        option.unfold(new object.Node(elem), object);
      }
    }

    //开始关闭所有子文件
    var ul = elem.nextElementSibling;
    if (notNull(ul)) {
      var lis = ul.childNodes;
      for (var i in lis) {
        var li = lis.item(i);
        if (li instanceof HTMLElement) {
          this.nodeFold(li.firstElementChild, false);
        }
      }
    }

  },
  nodeUnfold: function (elem, call) {
    if (elem instanceof object.Node) {
      elem = elem.elem;
    }

    if (!option.loadAll) {
      var li = elem.parentNode;
      var afterData = li.getAttribute('after-data');
      if (notNull(afterData)) {
        var data = JSON.parse(afterData);
        var div, click;
        if (option.checkbox) {
          div = li.firstElementChild.firstElementChild.childNodes[1];
          var span = div.firstElementChild.firstElementChild.className;
          if (span.indexOf("tree-checkbox-background-all") != -1) {
            click = true;
            this.checkboxClick(div);
          }
        }
        this.createElement(li, data[object.format.childs], data[object.format.unfold]);
        if (option.checkbox && click) {
          this.checkboxClick(div);
        }
        li.removeAttribute('after-data');
      }
    }
    var icon = elem.firstElementChild.firstElementChild;
    if (icon.className.indexOf('tree-title-icon') != -1) {
      return;
    }
    var fold = icon.nextElementSibling;
    if (option.checkbox) {
      fold = fold.nextElementSibling;
    }
    if (isFunction(option.prevUnFold)) {
      option.prevUnFold(new object.Node(elem), object);
    }
    icon.setAttribute('fold', true);
    icon.src = this.Icon.icon_fold.src;
    fold.src = this.Icon.dir_fold.src;
    addClass(elem.nextElementSibling, 'tree-fold');
    if (call) {
      if (isFunction(option.fold)) {
        option.fold(new object.Node(elem), object);
      }
    }
  },
  addData: function (key, data) {
    this.allData[key] = data;
  },
  getDataById: function (id) {
    if (notNull(this.allData)) {
      return this.allData[id];
    }
    return null;
  },
  createIcon: function (iconOption) {
    var img = document.createElement("img");
    if (notNull(iconOption.width) && notNull(iconOption.height)) {
      img.width = iconOption.width;
      img.height = iconOption.height;
    } else {
      img.width = 16;
      img.height = 16;
    }
    if (iconOption.src) {
      img.src = iconOption.src;
    }
    img.className = "tree-title-icon";
    return img;
  },
  checkboxClick: function (checkbox) {
    this.checkboxSelect(checkbox, true, 0, true, true, true);
  },
  checkboxSelect: function (elem, auto, type, andParent, onlyParent, child) {
    if (notNull(elem.className) && (andParent || !onlyParent)) {
      if (auto) {
        type = 0;
        var background = elem.firstElementChild.firstElementChild.className;
        if (background.indexOf('tree-checkbox-background-all') != -1 ||
          background.indexOf('tree-checkbox-background-notall') != -1) {
          this.setUnCheck(elem);
          type = 3;
        } else {
          this.setChecked(elem);
          type = 1;
        }
      } else {
        if (type == 1) {
          this.setChecked(elem);
        } else if (type == 2) {
          this.setCheckedNotAll(elem);
        } else if (type == 3) {
          this.setUnCheck(elem);
        }
      }
    } else {
      return;
    }

    //向下设置
    var ul = elem.parentNode.parentNode.nextElementSibling;
    if (notNull(ul) && child) {

      var lis = ul.childNodes;
      if (lis.length > 0) {
        for (var i in lis) {
          var li = lis.item(i);
          if (li instanceof HTMLLIElement) {
            var div = li.firstElementChild.firstElementChild.firstElementChild;
            if (div.className.indexOf("tree-fold-icon") != -1) {
              div = div.nextElementSibling;
            }
            this.checkboxSelect(div, false, type, false, false, true);
          }
        }
      }
    }

    //向上设置
    var parentUl = elem.parentNode.parentNode.parentNode.parentNode;
    if (notNull(parentUl) && andParent && onlyParent) {
      if (parentUl.nodeName.toUpperCase() != 'UL') {
        return;
      }

      lis = parentUl.childNodes;
      if (lis.length > 0) {
        var allSelect = true;
        var allNotSelect = true;
        var notAll = false;
        for (var i in lis) {
          var li = lis.item(i);
          if (li instanceof HTMLLIElement) {
            var div = li.firstElementChild.firstElementChild.firstElementChild;
            if (div.className.indexOf("tree-fold-icon") != -1) {
              div = div.nextElementSibling;
            }
            var span = div.firstElementChild.firstElementChild.className;
            //但凡有一个是不选中的，父类就要设置为不完全选中，如果全部为不选中的，则设置父类为不选中
            //没有选中
            if (span == 'tree-checkbox-background' || span == 'tree-checkbox-background tree-checkbox-background-notall') {
              allSelect = false;
            }
            //选中
            if (span.indexOf("tree-checkbox-background-all") != -1 || span.indexOf('tree-checkbox-background-notall') != -1) {
              allNotSelect = false;
            }
            if (span.indexOf('tree-checkbox-background-notall') != -1) {
              notAll = true;
            }
          }
        }

        if (parentUl.parentNode.className.indexOf('tree-main') == -1) {
          var div = parentUl.previousElementSibling.firstElementChild.childNodes[1];
          if (!allNotSelect && !allSelect || notAll) {
            this.checkboxSelect(div, false, 2, true, true, false);
          }
          if (allNotSelect) {
            this.checkboxSelect(div, false, 3, true, true, false)
          }
          if (allSelect) {
            this.checkboxSelect(div, false, 1, true, true, false);
          }
        }
      }
    }
  },
  setChecked: function (elem) {
    removeClass(elem.firstElementChild.firstElementChild, 'tree-checkbox-background-notall');
    addClass(elem.firstElementChild.firstElementChild, 'tree-checkbox-background-all');
  },
  setCheckedNotAll: function (elem) {
    removeClass(elem.firstElementChild.firstElementChild, 'tree-checkbox-background-all');
    addClass(elem.firstElementChild.firstElementChild, 'tree-checkbox-background-notall');

  },
  setUnCheck: function (elem) {
    removeClass(elem.firstElementChild.firstElementChild, 'tree-checkbox-background-notall');
    removeClass(elem.firstElementChild.firstElementChild, 'tree-checkbox-background-all');
  },
  getNotLoadId: function (data, arr) {
    if (!notNull(data) || option.loadAll) {
      return;
    }
    if (typeof data == 'string') {
      data = JSON.parse(data);
    }
    if (JSON.stringify(data).substr(0, 1) == '{') {
      var array = [];
      array[0] = data;
      data = array;
    }
    for (var i in data) {
      var d = data[i];
      var childs = d[object.format.childs];
      arr.add(d[object.format.id]);
      if (notNull(childs) && childs.length > 0) {
        this.getNotLoadId(childs, arr);
      }
    }

  },
  hasChildArray: function (data) {
    return notNull(data[object.format.childs]) && data[object.format.childs].length > 0;
  },
  loadInfo: function () {
    this.div_Load = document.createElement('div');
    this.div_Load.className = 'tree-load';
    this.div_Load.style.width = object.parent.style.width;
    var p = document.createElement('p');
    p.style.width = object.parent.style.width;
    p.style.height = (object.parent.style.fontSize || 20) + "px";
    p.innerHTML = option.loadText || '正在加载数据中，请稍后...';
    this.div_Load.appendChild(p)
    object.parent.appendChild(this.div_Load);
  }
}
